#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>  //http://www.gnu.org/software/libc/manual/html_mono/libc.html (API)
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFSIZE 256

void parsear(char string[],int* ar, char *argv[]);
char * buscar(char p[],char aux[]);
int  haybarra(char p[]);
char *camino_absoluto(char p[],char aux[],char *coman[]);
void modifica_comando(char x[]);

int main(void)
{       int h=0;
                
        char *argu[BUFFSIZE+1];
        int arguc;
        char *argu2[BUFFSIZE+1];
        int arguc2;
        char prompt[BUFFSIZE+1];
        char hostname[BUFFSIZE+1];
        char primera[BUFFSIZE+1];
        char primera2[BUFFSIZE+1];
        char segunda[BUFFSIZE+1];
        char entrada[BUFFSIZE+1];
        char paath[BUFFSIZE+1];
        char paath2[BUFFSIZE+1];
        char aux[BUFFSIZE+1];
        char *comando[BUFFSIZE+1];
        char *comando2[BUFFSIZE+1];
        char *seborra[BUFFSIZE+1];
        char parado[BUFFSIZE+1];
        char parado2[BUFFSIZE+1]; //Para laburar asi no pierdo parado.
        int flag;       // Bandera paralelismo
        int flag2; //Bandera >
        int flag3; // Bandera <
        int flagpipe; //cuando se encuentra el '|'
        char file[BUFFSIZE+1];
        char *parte1[BUFFSIZE+1];
                char *parte2[BUFFSIZE+1];
       
       
        parado[0]='\0';
        strcat(parado,"/home");
        chdir(parado);
        
                
       
        while(1){
                for(h=0;h<BUFFSIZE;h++){argu[h]=NULL;}
                for(h=0;h<BUFFSIZE;h++){argu2[h]=NULL;}
        flag = 0;             // Reseteamos la bandera de "paralelismo de ejecucion"
        flag2 = 0;
        flagpipe = 0;
        prompt[0]='\0';       //Ponemos el caracter nulo para que el 'strcat' empieze a concatenar desde el principio
        gethostname(hostname,BUFFSIZE+1);  //Obtenemos el hostname, funcion de la libreria gnu 'unistd.h'
        strcat(prompt,getlogin()); //Empezamos a armar el prompt, le metemos el loguin
        strcat(prompt,"@");     //Le ponemos el @
        strcat(prompt,hostname);  //Le ponemos el $
        //--------------------------------------------------
        char hostid[10];
        sprintf(hostid, "%lu", gethostid());
        strcat(prompt," ");
        strcat(prompt,hostid);
        //--------------------------------------------------
        strcat(prompt," $ ");   //Le ponemos el $
        strcat(prompt,getcwd(NULL,0));  //Le ponemos el directorio actual
        strcat(prompt,": ");  //Le ponemos los :
        argu[0]=NULL;             //Borramos tanto argc como argv para que cada vez que entre
        arguc=0;                  //no tenga valores guardados anteriormente                                                       
        paath[0]='\0';            //Borramos el paath
        argu2[0]=NULL;            //Borramos tanto argc como argv para que cada vez que entre
        arguc2=0;                 //no tenga valores guardados anteriormente                                                       
        paath2[0]='\0';           //Borramos el paath
        printf("%s",prompt);      //Mostramos prompt
       
        fgets(entrada,BUFFSIZE,stdin);      // Tomamos del stdin y guardamos en entrada
        entrada[strlen(entrada)-1]='\0';    //Agregamos un caracter nulo al final
       
        
        if((strstr(entrada,"|"))==NULL)   //Comprobamos el string 'entrada' que contenga el caracter '|' y agarramos el string a partir de ese caracter
        { parte1[0]=entrada;              // Si no esta el '|' entra a esta parte de if, y la guarda toda la entrada en parte1
        }
        else{         //si esta el '|'
        flagpipe=1;            //flagpipe = 1 cuando se encuentra '|' y 
         *parte1 = strtok (entrada,"|");         // Vamos dividiendo el string de entrada 
         *parte2 = strtok (NULL, "|");           // Volvemos a buscar (le mandamos null porque strtok al llamarla por segunda vez ya te guarda donde quedo la anterior, si volvemos a poner el string entrada en vez de null, estariamos seteando)
         if(strtok(NULL,"|")!=NULL){printf("ERROR: Solo se admite un PIPE a la vez\n");strcpy(paath,"@");}  //Si volvemos a encontrar otro '|' en el mismo string entrada, mandamos un mensaje de error
        }
        
        parsear(*parte1,&arguc,argu);  // Llamamos a parsear y le pasamos la entrada, argc y argv[] para que los modifique
        if(flagpipe!=1){               //Si no hay pipe, vemos si es exit
                        if(strcmp(argu[0],"exit")==0)    // Si es exit BREAK!!
        {break;
        }
                                                }                               
        else{parsear(*parte2,&arguc2,argu2);}    //Si hay pipe, llamamos a parsear para el 2º comando tambien.
        
       
        strcpy(primera,argu[0]);                                        // Tomo desde argv 0 y lo pongo en primera
        char k;
        sscanf(primera,"%c",&k);                                        //Tomamos el primer caracter de primera y lo ponemos en k
             
        switch(k){
                case '/':                                               //El 1 caracter es "/".Es camino ABSOLUTO
                strcpy(paath,camino_absoluto(primera,aux,comando));     //Aquí ya obtenemos el camino absoluto y el comando respectivo
                 if(access(paath,F_OK)==-1){strcpy(paath,"!");}         //Chequeamos si existe el path. Sino, pone !
                break;
                case '.':                                               //El primer caracter es punto
                {sscanf(primera,"%*c" "%c",&k);                         //Vamos a analizar el segundo caracter
                       
                 switch(k){
                         case '.':                                      //El 2 caracter es punto
                         {
                          sscanf(primera,"%*c" "%*c" "%c",&k);          //Vemos en 3 caracter
                          if(k=='/'){                                   //El 3 carcater es "/".Camino Relativo.Vuelvo un directorio y trato de ir.
                                                                  parado2[0]='\0';
                                  strcpy(primera,strstr(primera,"/"));  //Saca los dos primeros puntos
                                  strcpy(paath,camino_absoluto(primera,aux,comando));// Aquí ya obtenemos el camino y el comando respectivo    
                                  strcpy(parado2,camino_absoluto(parado,aux,seborra)); //En paath tengo el camino vuelto uno
                                  strcat(parado2,paath);                                //en parado2 tengo el camino absoluto.
                                  if(access(parado2,F_OK)==-1){strcpy(paath,"!");printf("ERROR: No existe el archivo o directorio\n");} //Chequeamos si existe el path. Sino, pone !
                                  else{strcpy(paath,parado2);}                                  //Si existe lo copia en paath
                                   }                                                                            
                          else{strcpy(paath,"@");printf("ERROR: Error de sintaxis\n");}    //El tercer caracter no era una barra, y eso da ERROR.
                                 }
                         break;
                         case '/':                                      //El segundo caracter es "/".Es camino RELATIVO. (intenta ejecutar desde donde estoy).
                         {
                          sscanf(primera,"%*c" "%s",primera);                   //Sacamos el primer punto
                          strcpy(paath,camino_absoluto(primera,aux,comando)); //Devuelve el paath y el comando
                          strcpy(parado2,parado);                                               //Copia parado a parado2 para no perder el 1ro.
                          strcat(parado2,paath);                                                //Agrega el path a donde estoy para chequar si existe.
                          if(access(parado2,F_OK)==-1){strcpy(paath,"!");}                      //Chequeamos si existe el path. Sino, pone !
                                                  else{strcpy(paath,parado2);}
                         }
                         break;
                         default:                                                                //El 2 caracter no es ni punto ni barra,es letra y da ERROR
                         strcpy(paath,"@"); printf("ERROR: Error de sintaxis\n");    
                         break;}
                 break;
                        }
                 default:                                        //El 1 caracter no es ni punto ni barra. Es una letra
                 {
                                        if((strstr(argu[0],"/"))!=NULL){strcpy(paath,"!");}//Si llegado a este punto el primer argumento tiene barra, hay ERROR.
                                        else{
                                                if(strcmp(argu[0],"cd")==0){                                    //El primer argumento es cd
                                                if(flagpipe==1){printf("ERROR: No se puede utilizar 'cd' con PIPES\n");break;}
                                                
                                                strcpy(segunda,argu[1]);                        // Tomo desde argv 1 y lo pongo en segunda
                                                char k2;
                                                sscanf(segunda,"%c",&k2);
                                                strcpy(segunda,argu[1]);        
                                                switch (k2){                                                                            //Vamos a analizar el primer caracter de segunda
                                                case '/':                                                                               //El primer caracter es /, es camino absoluto desde la raiz
                                                {
                                                                                                 if(access(segunda,F_OK)==-1){strcpy(paath,"!");printf("ERROR: No existe el archivo o directorio\n");}//Chequeamos si existe el path. Sino, pone !
                                                 else{strcpy(paath,segunda);}
                                                 chdir(paath);                                                                  //Se posiciona
                                                 strcpy(parado,paath);
                                                }
                                                break;
                                                case '.':                                                                          //El primer caracter es .
                                                {if(strcmp(segunda,"..")==0)
                                                        {strcpy(parado2,camino_absoluto(parado,aux,seborra));// En parado2 tengo el parado vuelto en uno
                                                         if(parado2[0]=='\0'){chdir("/");strcpy(parado,"/");}// Cuando tengo que volver a la raiz
                                                         chdir(parado2);                                                                         // Me posiciono en parado2             
                                                         strcpy(parado,parado2);                                                        // Actualizo posición   
                                                        }
                                                 else{sscanf(segunda,"%*c" "%c",&k2);                                                   // El segundo no es ..
                                                          
                                                          if(k2=='/')
                                                          {strcpy(aux,strstr(segunda,"/"));                             //Saca el primer punto
                                                           strcpy(parado2,parado);
                                                           strcat(parado2,aux);
                                                           if(access(parado2,F_OK)==-1){strcpy(paath,"!");printf("ERROR: No existe el archivo o directorio\n");}                     //Chequeamos si existe el path. Sino, pone !
                                                                else{chdir(parado2);strcpy(parado,parado2);}
                                                          }
                                                          else{ char k3;                                                                                                // No es ./
                                                                  sscanf(segunda,"%*c" "%*c" "%c",&k3);
                                                                  if(k2=='.' && k3=='/')                                                                        // Es ../
                                                                  {     strcpy(parado2,camino_absoluto(parado,aux,seborra));
                                                                        strcpy(aux,strstr(segunda,"/"));
                                                                        strcat(parado2,aux);
                                                                        if(access(parado2,F_OK)==-1){strcpy(paath,"!");printf("ERROR: No existe el archivo o directorio\n");}                        //Chequeamos si existe el path. Sino, pone !
                                                                                else{chdir(parado2);strcpy(parado,parado2);}
                                                                        aux[0]='\0';
                                                                        }
                                                                        else{strcpy(paath,"@");printf("ERROR: Error de sintaxis\n");}
                                                                        }
                                                          }     
                                                }
                                                break;
                                                default:
                                                {strcpy(segunda,argu[1]);
                                                 strcpy(parado2,parado);
                                                 strcat(parado2,"/");
                                                 strcat(parado2,segunda);
                                                 
                                                 if(access(parado2,F_OK)==-1){strcpy(paath,"!");printf("ERROR: No existe el archivo o directorio\n");}                       //Chequeamos si existe el path. Sino, pone !
                                                                                else{
																					chdir(parado2);strcpy(parado,parado2);
																					}
                                                 }
                                                
                                                }}
                                                else{                  // El primer argumento no es CD!!
                                                      strcpy(paath,buscar(primera,aux));
                                                      comando[0]=primera;
                                                                                                        }
                                                 
                                                }
                                 }
                 break;
                }
                                
                                
               
                                                                int h;
                                for(h=0;h<BUFFSIZE;h++){                // Vamos recorriendo argv en busca de >
                                        
                                                if(strcmp(argu[h],"<")==0){
                                                                                                if(flagpipe==1){printf("ERROR: Solo se admite un operador a la vez: [>],[<],[&] o [|]\n");break;}
                                                flag3=1;                // Si esta, levantamos bandera "flag2" de redireccion
                                                strcpy(file,argu[h+1]); // Guardamos el proximo argv en file.
                                        }       

                                        if(strcmp(argu[h],">")==0){
                                                                                                if(flagpipe==1){printf("ERROR: Solo se admite un operador a la vez: [>],[<],[&] o [|]\n");break;}
                                                flag2=1;                // Si esta, levantamos bandera "flag2" de redireccion
                                                strcpy(file,argu[h+1]); // Guardamos el proximo argv en file.
                                        }       
                                        if(strcmp(argu[h],argu[arguc-1])==0){break;}                     //Si llegamos al final de argv, break.
                                        }
               
               if(strcmp(argu[arguc-1],"&")==0){argu[arguc-1]=NULL;flag=1; //Vemos si la ultima cadena de argv es un &.Si es, lo borramos, y levantamos la flag de paralelismo.
                                           if(flagpipe==1){printf("ERROR: Solo se admite un operador a la vez: [>],[<],[&] o [|]\n");break;}}
                         
                         aux[0]='\0';
                      //   parado[0]='\0';
                         parado2[0]='\0';
                         *seborra=NULL;
                         if(flagpipe==1){
                                  
                                 strcpy(primera2,argu2[0]);                                        // Tomo desde argv 0 y lo pongo en primera
        char k;
        sscanf(primera2,"%c",&k);                                                                                //Tomamos el primer caracter de primera y lo ponemos en k
           
        switch(k){
                case '/':                                               //El 1 caracter es "/".Es camino ABSOLUTO
                strcpy(paath2,camino_absoluto(primera2,aux,comando2));     //Aquí ya obtenemos el camino absoluto y el comando respectivo      
                 if(access(paath2,F_OK)==-1){strcpy(paath2,"!");printf("ERROR: No existe el archivo o directorio\n");}                 //Chequeamos si existe el path. Sino, pone !
                break;
                case '.':                                               //El primer caracter es punto
                {sscanf(primera2,"%*c" "%c",&k);                         //Vamos a analizar el segundo caracter
                       
                 switch(k){
                         case '.':                                      //El 2 caracter es punto
                         {
                          sscanf(primera2,"%*c" "%*c" "%c",&k);          //Vemos en 3 caracter
                          if(k=='/'){                                   //El 3 carcater es "/".Camino Relativo.Vuelvo un directorio y trato de ir.
                                  parado2[0]='\0';
                                  strcpy(primera2,strstr(primera2,"/"));  //Saca los dos primeros puntos
                                  strcpy(paath2,camino_absoluto(primera2,aux,comando2));// Aquí ya obtenemos el camino y el comando respectivo    
                                  strcpy(parado2,camino_absoluto(parado,aux,seborra)); //En paath tengo el camino vuelto uno
                                  strcat(parado2,paath2);                                //en parado2 tengo el camino absoluto.
                                  if(access(parado2,F_OK)==-1){strcpy(paath2,"!");printf("ERROR: No existe el archivo o directorio\n");}      //Chequeamos si existe el path. Sino, pone !
                                  else{strcpy(paath2,parado2);}                                  //Si existe lo copia en paath
                                   }                                                                            
                          else{strcpy(paath2,"@");printf("ERROR: Error de sintaxis\n");}                                      //El tercer caracter no era una barra, y eso da ERROR.
                                 }
                         break;
                         case '/':                                      //El segundo caracter es "/".Es camino RELATIVO. (intenta ejecutar desde donde estoy).
                         {
                          sscanf(primera2,"%*c" "%s",primera2);                   //Sacamos el primer punto
                          strcpy(paath2,camino_absoluto(primera2,aux,comando2)); //Devuelve el paath y el comando
                          strcpy(parado2,parado);                                               //Copia parado a parado2 para no perder el 1ro.
                          strcat(parado2,paath2);                                                //Agrega el path a donde estoy para chequar si existe.
                          if(access(parado2,F_OK)==-1){strcpy(paath2,"!");printf("ERROR: No existe el archivo o directorio\n");}                      //Chequeamos si existe el path. Sino, pone !
                                                  else{strcpy(paath2,parado2);}
                         }
                         break;
                         default:                                                                //El 2 caracter no es ni punto ni barra,es letra y da ERROR
                         strcpy(paath2,"@"); printf("ERROR: Error de sintaxis\n");    
                         break;}
                 break;
                        }
                 default:                                        //El 1 caracter no es ni punto ni barra. Es una letra
                 { 
                                        if((strstr(argu2[0],"/"))!=NULL){strcpy(paath2,"@");printf("ERROR: Error de sintaxis\n");}//Si llegado a este punto el primer argumento tiene barra, hay ERROR.
                                        else{
                                                if(strcmp(argu2[0],"cd")==0){                                    //El primer argumento es cd
                                                if(flagpipe==1){printf("ERROR: No se puede utilizar 'cd' con PIPES\n");break;}
                                                
                                               }
                                                else{                  // El primer argumento no es CD!!
                                                     
                                                      strcpy(paath2,buscar(primera2,aux));
                                                      comando2[0]=primera2;
                                                                                                        }
                                                 
                                                }
                                 }
                 break;
                }
                                 
                                 
                                 }

//printf("primer comando: %s\n",paath);
//printf("segundo comando: %s\n",paath2);                        
if(strcmp(paath,"!")==0 || strcmp(paath,"@")==0 || strcmp(paath2,"!")==0 || strcmp(paath2,"@")==0 ){  }
else{
int p[2];
pipe(p);
int s;
s = fork();                                                             //Tenemos el idproceso en S
if (s==0) {                                                             //Si s es cero trabajamos con el hijo (xq para el hijo, s vale cero).

char completo[BUFFSIZE+1];
completo[0]='\0';
strcat(completo,paath);strcat(completo,"/");strcat(completo,*comando);  //Concatenamos en completo el path y el comando para llamar a execv.

if(flag2==1){                                                           // Si esta levantada la bandera de redireccion de salida, borramos los ultimos 2 argumentos de argv y redireccionamos al file.
                        argu[h]=NULL;
                        argu[h-1]=NULL;
                        freopen( file, "w", stdout);
            }
if(flag3==1){                                                           //La bandera de redireccion de entrada esta levantada
                   
                    argu[h-1]='\0';
                    
         
                    
                  
        int fid;
		int flags,perm,STDIN_FID;
		STDIN_FID=0;
		flags = O_RDONLY;
		perm = S_IWUSR|S_IRUSR;
		fid = open(file, flags, perm);
		if (fid<0) { 
				printf("Error: archivo no valido\n");
				exit(0); }
		close(STDIN_FID); /* stdout def. en stdio.h es un FILE* */
		if (dup(fid)<0) { printf("ERROR"); exit(1); }
	
		close(fid); 
                       
                                                
             }
if(flagpipe==1){
                                
                                                close(p[0]); // cerramos el lado de lectura del pipe 
                                                dup2(p[1], 1); // STDOUT = extremo de salida del pipe 
                                                close(p[1]); // cerramos el descriptor de fichero que sobra tras el dup2 
                         }
execv(completo,argu);
return 0;
/*no quiero nietos!*/
}
else
{
if(flag!=1){                                                           // Preguntamos por la flag de paralelismo. Si no esta levantada (no ingresaron &), el padre espera al hijo.
int status;

waitpid(s,&status,0);                                                  //Modificar este comando para que el padre espere al hijo
            }
if(flagpipe==1){
        int id;
        id= fork();
        if(id==0){
        char completo[BUFFSIZE+1];
        completo[0]='\0';
        strcat(completo,paath2);strcat(completo,"/");strcat(completo,*comando2);  //Concatenamos en completo el path y el comando para llamar a execv.
        close(p[1]); // cerramos el lado de escritura del pipe 
    dup2(p[0], 0); // STDIN = extremo de entrada del pipe 
    close(p[0]); // cerramos el descriptor de fichero que sobra tras el dup2 
    execv(completo,argu2);
    return 0;
    }
        else{
			close(p[0]);close(p[1]);
        int stat;
        waitpid(id,&stat,0);
                }
        
    
    
    }
     
}}///////////////

   
        }//while
     
        return 0;  
}//main


void parsear(char string[],int *ar, char *argu[])
{      
        char *palabra[BUFFSIZE+1];

         *palabra = strtok (string," ");                                // Vamos dividiendo el string de entrada para luego cargarlo en el arv[]
                while (*palabra != NULL)                                        // El while va a recorrer hasta el final del string
                {      
                        argu[(*ar)]=*palabra;                                   // Cargamos en argv[] la palabra parseada en el lugar ar que corresponde
                        (*ar)++;                                                // ar aumenta en cada pasada
                        *palabra = strtok (NULL, " ");                  // Volvemos a buscar
                }
}

char* buscar(char p[],char aux[])
{       char *x[BUFFSIZE+1];
        char cadena[BUFFSIZE+1];
        char *devolver[BUFFSIZE+1];                                     // chequear luego si el comando está en el PATH
        char camino[BUFFSIZE+1];
        
        x[0]=getenv("PATH");
        strcpy(cadena,*x);                                                                                              // En cadena vamos a tener guardado todo el PATH
                                                                                                                        
        *devolver=strtok(cadena,":");                                   // Guardamos en devolver la primer ruta del PATH

        while(*devolver !=NULL)                                         // Hasta que no vaciemos "cadena" buscando en el PATH no paramos
        {
                 strcpy(camino,*devolver);                                                                              // Copiamos en camino y en aux el path actual
                 strcpy(aux,*devolver); 
                 *devolver = strtok (NULL,":");                                                                 // Obtenemos el siguiente path antes de trabajar con el actual
                 strcat(camino,"/");strcat(camino,p);                                                   // Agregamos el comando al final de camino (va teniendo las distintas rutas del PATH). 
                                    
        if(access(camino,F_OK)==-1){}                                                                   // Si no existe la ruta completa (camino + comando, no hace nada y vuelve a entrar con el camino que sigue.
        else{
                        return aux;}                                                                                            // Si existe, devolvemos aux (que era el camino anterior).
        }
        strcpy(aux,"!");  printf("ERROR: No existe el archivo o directorio\n");                                                                                              // Si salio del while, no encontro el comando en ningun camino del PATH. Ponemos el "!".
        return aux;
}

int haybarra(char p[])
{       char *b[BUFFSIZE+1];
        *b=strtok(p,"/");
        if(strcmp(p,*b)==0){return 0;}
        else{return 1;}
}

char *camino_absoluto(char p[],char aux[],char *coman[])
{       char *absoluto[BUFFSIZE+1];                                                                                     // Con absoluto recorremos la entrada que es p[]
        char *buf[BUFFSIZE+1];                                                                                          // En cada lugar de buf vamos a guardar lo que está entre barras
       
        int aux2=0;                                                                                                                     // Con aux2 nos movemos dentro del array buf
        int i=0;                                                                                                                        // i para el for
        aux[0]='\0';                                                                                                            // Borramos aux para que cada vez que entre no tenga guardado el paath anterior
       
        *absoluto = strtok (p,"/");                                                                                     // Vamos separando todo p y ademas agregamos a buf
                while (*absoluto != NULL)                                      
                {      
                       
                        buf[aux2]=*absoluto;
                        aux2=aux2+1;
                        *absoluto=strtok(NULL,"/");
                               
                }                                                                                                                               // Sacamos de buf y ponemos en aux con las barras para tener el camino absoluto
               
                for(i=0;i<aux2-1;i++)
                {strcat(aux,"/");
                 strcat(aux,buf[i]);}                                                                                   // Una vez que ya tenemos armado aux, el último valor de buf debe ser guardado en coman
                 aux2=aux2-1;                                                                                                   // ya que ese útlimo valor es el comando.
                coman[0]=buf[aux2];
               
        return aux;
}
